#include "rtpsender.h"
#include <QDebug>

#include <QCoreApplication>
#include <QDir>

RtpSender::RtpSender(quint16 clientPort, quint16 serverPort,QString filePath)
    : m_clientPort(clientPort)
    , m_serverPort(serverPort)
    , m_filePath(filePath)
{

}

void RtpSender::run()
{
    QUdpSocket socket;
    if (!socket.bind(QHostAddress("127.0.0.1"), m_serverPort))
    {
        qWarning() << "Bind failed";
        return;
    }

    //打开exe所在路径下的文件
    QString exeDir = QCoreApplication::applicationDirPath();
    QString filePath = exeDir + "/" + m_filePath;
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly))
    {
        qWarning() << "File open failed";
        return;
    }

    quint16 seqNum = 0;
    quint32 timestamp = 0;
    const quint32 ssrc = 0x12345678;
    const quint8 payloadType = 96; // H.264动态类型

    bool bsimpltest = false;
    if(bsimpltest)
    {
        //简单测试RTP发送数据，可以简单了解nal的发送过程，将bsimpltest=true测试
        RtpSendSimpleTest(&socket);
    }
    else
    {
        //从h264文件获取nal发送
        while (!file.atEnd())
        {
            //从文件获取nal
            //（这里没有实现分片处理，udp传输数据限制1400多字节，nal大小超出需要进行分片传输，否则推送会有丢失的情况）
            QByteArray nal = getNextNalUnit(file);
            if (nal.size() <= 0)
            {
                qInfo() << "nal empty";
                break;
            }

            qInfo() << nal.toHex();
            // 封装RTP包
            QByteArray packet = buildRtpPacket(nal, payloadType, seqNum, timestamp, ssrc);
            //发送RTP
            socket.writeDatagram(packet, QHostAddress("127.0.0.1"), m_clientPort);

            seqNum++;
            timestamp += 3000; // 按30fps递增
        }
    }
    file.close();
}

//给传入的nal加上RTP头
QByteArray RtpSender::buildRtpPacket(const QByteArray& nal, quint8 payloadType,
                          quint16 seqNum, quint32 timestamp, quint32 ssrc)
{
    QByteArray packet;
    packet.resize(12 + nal.size()); // 12字节头部 + NAL数据

    // RTP头部构造
    quint8 header[12];
    packet[0] = 0x80; // V=2, P=0, X=0, CC=0
    packet[1] = payloadType & 0x7F;
    packet[2] = (seqNum >> 8) & 0xFF;
    packet[3] = seqNum & 0xFF;
    // 写入timestamp和ssrc...
    // 写入timestamp（网络字节序）
    packet[4] = (timestamp >> 24) & 0xFF;
    packet[5] = (timestamp >> 16) & 0xFF;
    packet[6] = (timestamp >> 8) & 0xFF;
    packet[7] = timestamp & 0xFF;

    // 写入SSRC（网络字节序）
    packet[8] = (ssrc >> 24) & 0xFF;
    packet[9] = (ssrc >> 16) & 0xFF;
    packet[10] = (ssrc >> 8) & 0xFF;
    packet[11] = ssrc & 0xFF;

    // 填充NAL数据
    memcpy(packet.data()+12, nal.constData(), nal.size());
    return packet;
}

//从文件中逐个解析出nal并返回
QByteArray RtpSender::getNextNalUnit(QFile& file)
{
    static const quint32 START_CODE_4 = 0x00000001;
    static const quint32 START_CODE_3 = 0x000001;
    QByteArray nalUnit;
    quint32 window = 0;

    while (!file.atEnd())
    {
        char byte;
        if (!file.getChar(&byte)) break;

        // 更新滑动窗口
        window = (window << 8) | (quint8)byte;
        nalUnit.append(byte);

        // 检测4字节起始码
        if ((window & 0xFFFFFFFF) == START_CODE_4)
        {
            if (nalUnit.size() > 4)
            {
                // 返回前一个NALU（不含当前起始码）
                QByteArray result = nalUnit.left(nalUnit.size() - 4);
                file.seek(file.pos() - 4); // 回退起始码位置
                return result;
            }
            nalUnit.clear(); // 清除无效数据
        }
        // 检测3字节起始码
        else if ((window & 0xFFFFFF) == START_CODE_3)
        {
            if (nalUnit.size() > 3) {
                QByteArray result = nalUnit.left(nalUnit.size() - 3);
                file.seek(file.pos() - 3);
                return result;
            }
            nalUnit.clear();
        }
    }

    // 文件末尾处理
    if (!nalUnit.isEmpty())
    {
        // 检查是否为纯起始码（无有效数据）
        if (nalUnit.size() == 4 &&
            *reinterpret_cast<const quint32*>(nalUnit.constData()) == START_CODE_4)
        {
            return QByteArray();
        }
        if (nalUnit.size() == 3 &&
            (*reinterpret_cast<const quint16*>(nalUnit.constData()) == 0) &&
            (quint8)nalUnit[2] == 1)
        {
            return QByteArray();
        }
        return nalUnit;
    }

    return QByteArray();
}

//简单测试RTP发送数据
void RtpSender::RtpSendSimpleTest(QUdpSocket *  socket)
{
    quint16 seqNum = 0;
    quint32 timestamp = 0;
    const quint32 ssrc = 0x12345678;
    const quint8 payloadType = 96; // H.264动态类型

    //h264的几类数据
    //SEI 补充增强信息  0000000106
    //SPS 序列参数集 0000000167
    //PPS 图像参数集 0000000168
    //IDR图像片 0000000165
    //非IDR图像片 0000000141

    //RTP发送数据，简单测试,测试效果，有黄色方块简短出现
    QByteArray byteArraySPS = QByteArray::fromHex("000000016742402995BA5B0110000003001000000303C8DA1C32E0");
    QByteArray byteArrayPPS = QByteArray::fromHex("0000000168CE3C80");
    QByteArray byteArrayIDR = QByteArray::fromHex("000000016588804FFFFFC11033140004DABC700013818E00021BD2727278");
    QByteArray byteArrayP = QByteArray::fromHex("000001419A023CB0");
    QByteArray byteArrayP2 = QByteArray::fromHex("000001419A");

    QByteArray packet = buildRtpPacket(byteArraySPS, payloadType, seqNum, timestamp, ssrc);
    socket->writeDatagram(packet, QHostAddress("127.0.0.1"), m_clientPort);
    seqNum++;
    timestamp += 3000; // 按30fps递增

    packet = buildRtpPacket(byteArrayPPS, payloadType, seqNum, timestamp, ssrc);
    socket->writeDatagram(packet, QHostAddress("127.0.0.1"), m_clientPort);
    seqNum++;
    timestamp += 3000;

    packet = buildRtpPacket(byteArrayIDR, payloadType, seqNum, timestamp, ssrc);
    socket->writeDatagram(packet, QHostAddress("127.0.0.1"), m_clientPort);
    seqNum++;
    timestamp += 3000;

    packet = buildRtpPacket(byteArrayP, payloadType, seqNum, timestamp, ssrc);
    socket->writeDatagram(packet, QHostAddress("127.0.0.1"), m_clientPort);
    seqNum++;
    timestamp += 3000;

    packet = buildRtpPacket(byteArrayP2, payloadType, seqNum, timestamp, ssrc);
    socket->writeDatagram(packet, QHostAddress("127.0.0.1"), m_clientPort);
    seqNum++;
    timestamp += 3000;
}
